package com.cheney.demo.util;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.cheney.common.core.exception.BaseException;
import com.cheney.demo.config.RedisCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 微信公众号工具类
 *
 * @author si.chen
 * @date 2021/3/30 10:27
 */
@Component
public class WechatOfficialAccountUtil {

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private RestTemplateUtils restTemplateUtils;

    @Value("${wx.officialAccount.appId}")
    private String appId;

    @Value("${wx.officialAccount.appSecret}")
    private String appSecret;

    /**
     * 获取微信accessToken
     * 分布式环境需要分布式锁
     * By restTemplate
     */
    public synchronized String getAccessToken() {
        String accessToken = redisCache.getCacheObject("cheney-platform:wx:officialAccount:accessToken");
        if (StrUtil.isBlank(accessToken)) {
            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type={grant_type}&appid={appid}&secret={secret}";
            Map<String, Object> param = new HashMap<>();
            param.put("grant_type", "client_credential");
            param.put("appid", appId);
            param.put("secret", appSecret);
            try {
                ResponseEntity<String> res = restTemplateUtils.get(url, String.class, param);
                JSONObject jsonObject = JSONObject.parseObject(res.getBody());
                accessToken = jsonObject.get("access_token").toString();
                if (StrUtil.isNotBlank(accessToken)) {
                    redisCache.setCacheObject("cheney-platform:wx:officialAccount:accessToken", accessToken, 7000, TimeUnit.SECONDS);
                } else {
                    throw new BaseException("获取微信accessToken出错");
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new BaseException("获取微信accessToken出错");
            }
        }
        return accessToken;
    }


    /**
     * 获取临时素材
     */
    public String getTempMediaUrl(String mediaId) throws IOException {
        String accessToken = getAccessToken();
        String url = "https://api.weixin.qq.com/cgi-bin/media/get";
        return url + "?" + String.format("access_token=%s&media_id=%s", accessToken, mediaId);
    }

    /**
     * 前端完成
     * 关于特殊场景下的静默授权
     * 1、上面已经提到，对于以snsapi_base为scope的网页授权，就静默授权的，用户无感知；
     * 2、对于已关注公众号的用户，如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页，即使是scope为snsapi_userinfo，也是静默授权，用户无感知。
     */
    public String getCode(String redirectUri, String scope, String state) {
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={appid}&redirect_uri={redirect_uri}&response_type={response_type}&scope={scope}&state={state}#wechat_redirect";
        Map<String, Object> param = new HashMap<>();
        param.put("appid", appId);
        param.put("redirect_uri", redirectUri);
        param.put("response_type", "code");
        //snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid）
        //snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。并且， 即使在未关注的情况下，只要用户授权，也能获取其信息 ）
        param.put("scope", scope);
        param.put("state", state);
        ResponseEntity<String> res = restTemplateUtils.get(url, String.class, param);
        return res.getBody();
    }

    /**
     * 通过code换取网页授权access_token和openid
     */
    public String getAccessTokenAndOpenId(String code) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={appid}&secret={secret}&code={code}&grant_type={grant_type}";
        Map<String, Object> param = new HashMap<>();
        param.put("appid", appId);
        param.put("secret", appSecret);
        param.put("code", code);
        param.put("grant_type", "authorization_code");
        ResponseEntity<String> res = restTemplateUtils.get(url, String.class, param);
        return res.getBody();
    }

    /**
     * 刷新access_token
     */
    public String refreshAccessToken(String refreshToken) {
        String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid={appid}&grant_type=refresh_token&refresh_token={refresh_token}";
        Map<String, Object> param = new HashMap<>();
        param.put("appid", appId);
        param.put("refresh_token", refreshToken);
        ResponseEntity<String> res = restTemplateUtils.get(url, String.class, param);
        return res.getBody();
    }

    /**
     * 拉取用户信息(需scope为 snsapi_userinfo)
     */
    public String getUserinfo(String openid) {
        String url = "https://api.weixin.qq.com/sns/userinfo?access_token={access_token}&openid={openid}&lang=zh_CN";
        Map<String, Object> param = new HashMap<>();
        param.put("access_token", getAccessToken());
        param.put("openid", openid);
        ResponseEntity<String> res = restTemplateUtils.get(url, String.class, param);
        return res.getBody();
    }

    /**
     * 获取jsapi签名
     */
    public synchronized String getJsTicket() {
        String jsTicket = redisCache.getCacheObject("cheney-platform:wx:officialAccount:jsTicket");
        if (StrUtil.isBlank(jsTicket)) {
            String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={access_token}&type=jsapi";
            Map<String, Object> param = new HashMap<>();
            param.put("access_token", getAccessToken());
            try {
                ResponseEntity<String> res = restTemplateUtils.get(url, String.class, param);
                JSONObject jsonObject = JSONObject.parseObject(res.getBody());
                if (ObjectUtil.isNotNull(jsonObject.get("ticket"))) {
                    jsTicket = jsonObject.get("ticket").toString();
                    redisCache.setCacheObject("cheney-platform:wx:officialAccount:jsTicket", jsTicket, 7000, TimeUnit.SECONDS);
                } else {
                    throw new BaseException("获取微信js-ticket出错");
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new BaseException("获取微信js-ticket出错");
            }
        }
        return jsTicket;
    }

    /**
     * 身份证识别
     */
    public String ocrIdcard(String type, String imgUrl) {
        String url = "https://api.weixin.qq.com/cv/ocr/idcard?type={type}&img_url={img_url}&access_token={access_token}";
        Map<String, Object> param = new HashMap<>();
        param.put("type", type);
        param.put("img_url", imgUrl);
        param.put("access_token", getAccessToken());
        ResponseEntity<String> res = restTemplateUtils.post(url, null, String.class, param);
        return res.getBody();
    }
}
